#include <QNetworkRequest>
#include "qqprotocol.h"


CVerifyCodeInfo::CVerifyCodeInfo()
{
    Reset();
}

CVerifyCodeInfo::~CVerifyCodeInfo()
{
}

void CVerifyCodeInfo::Reset()
{
    m_nNeedVerify = 0;
    m_strVerifyCode = "";
    m_strVCType = "";
}

int CVerifyCodeInfo::Parse(QByteArray &byteData)
{

    int iRet = YOUNG_ERROR;
    if ( byteData.length() == 0 )
        return iRet;

    Reset();
    QTextCodec *codec = QTextCodec::codecForName("utf8");

    // ptui_checkVC('0','!C4P', '\x00\x00\x00\x00\x32\x87\x00\x6c');
     QString RespDataW =  codec->toUnicode(byteData);
    if (0 == RespDataW.length())
        return iRet;

    //LPCTSTR lpFmt = _T("ptui_checkVC('%d','%[^']', '%[^']');");
    //_stscanf(lpRespDataW, lpFmt, &m_nNeedVerify, cTemp1, cTemp2);

    QString str = RespDataW;
    QString strTemp1, strTemp2, strTemp3;
    int nPos1 = str.indexOf("ptui_checkVC('");
    if (nPos1 >= 0)
    {
        nPos1 += QString("ptui_checkVC('").length();
        int nPos2 = str.indexOf(("','"), nPos1);
        if (nPos2 >= 0 )
        {
            strTemp1 = str.mid(nPos1, nPos2 - nPos1);
            if (strTemp1.length() != 0)
                m_nNeedVerify = strTemp1.toInt();

            nPos1 = nPos2+QString("','").length();
            nPos2 = str.indexOf(("','"), nPos1);
            if (nPos2 >= 0 )
            {
                strTemp2 = str.mid(nPos1, nPos2 - nPos1);

                nPos1 = nPos2+QString("','").length();
                nPos2 = str.indexOf(("');"), nPos1);
                if (nPos2 >= 0)
                    strTemp3 = str.mid(nPos1, nPos2 - nPos1);
            }
        }
    }

    if (m_nNeedVerify == 0)		// 不需要验证码
    {
        m_strVCType = ("");
        m_strVerifyCode = strTemp2;
        iRet = YOUNG_NEEDVERITY ;
    }
    else
    {
        m_strVCType = strTemp2;
        m_strVerifyCode = "";
        iRet = YOUNG_NONEEDVERITY;
    }

    m_nPtUinLen = sizeof(m_cPtUin) / sizeof(CHAR);
    return ParsePtUin((wchar_t*)strTemp3.toStdWString().c_str(), m_cPtUin, m_nPtUinLen);
}

int CVerifyCodeInfo::ParsePtUin(wchar_t * lpInPtUin, char * lpOutPtUin, int& nOutPtUinLen)
{
    int iRet = YOUNG_ERROR;
    nOutPtUinLen = 0;

    if (NULL == lpOutPtUin)
        return iRet;

    memset(lpOutPtUin, 0, nOutPtUinLen);

    if (NULL == lpInPtUin || NULL == *lpInPtUin)
        return iRet;

    wchar_t cTemp[3] = {0};

    int nInPtUinLen = QString::fromWCharArray(lpInPtUin).length();
    for (int i = 0; i < nInPtUinLen; i++)
    {
        if (lpInPtUin[i] == L'\\' && lpInPtUin[i+1] == L'x')
        {
            i += 2;
            if (i + 1 < nInPtUinLen && isalnum(lpInPtUin[i]) && isalnum(lpInPtUin[i+1]))
            {
                cTemp[0] = lpInPtUin[i];
                cTemp[1] = lpInPtUin[i+1];
                cTemp[2] = L'\0';
                lpOutPtUin[m_nPtUinLen] = QString::fromWCharArray(cTemp).toLong(0,16);
                m_nPtUinLen++;
                i += 1;
            }
            else
            {
                continue;
            }
        }
        else
        {
            continue;
        }
    }

    return YOUNG_GETVERITYCODE;
}



void CLoginResult_1::Reset()
{
    m_nRetCode = 0;
    m_strMsg = "";
    m_strPtWebQq = "";
    m_strSKey = "";
}
int  CLoginResult_1::Parse(QByteArray * lpBuf, std::vector<QString>* arrRespHeader)
{
    if (NULL == lpBuf || lpBuf->length() == 0 || NULL == arrRespHeader)
        return YOUNG_ERROR;

    Reset();
    QTextCodec *codec = QTextCodec::codecForName("utf8");
    QString RespDataW =  codec->toUnicode(*lpBuf);

    if(RespDataW.length() == 0)
    {
        return YOUNG_ERROR;
    }

    wchar_t *lpFmt = (L"ptuiCB('%d',%*[^,],%*[^,],%*[^,],'%[^']');");
    int nRetCode = -1;
    wchar_t cMsg[1024] = {0};

    swscanf(RespDataW.toStdWString().c_str(), lpFmt, &nRetCode, cMsg);

    m_nRetCode = nRetCode;
    m_strMsg = QString::fromWCharArray(cMsg);

//	HTTP/1.1 200 OK
//	Date: Tue, 26 Mar 2013 04:08:43 GMT
//  Server: Tencent Login Server/2.0.0
//  P3P: CP="CAO PSA OUR"
//  Set-Cookie: pt2gguin=o0847708268; EXPIRES=Fri, 02-Jan-2020 00:00:00 GMT; PATH=/; DOMAIN=qq.com;
//  Set-Cookie: uin=o0847708268; PATH=/; DOMAIN=qq.com;
//	Set-Cookie: skey=@9Nf6S5Mqa; PATH=/; DOMAIN=qq.com;
//	Set-Cookie: ETK=; PATH=/; DOMAIN=ptlogin2.qq.com;
//	Set-Cookie: ptuserinfo=e5beaee5b098; PATH=/; DOMAIN=ptlogin2.qq.com;
//	Set-Cookie: ptwebqq=b6940e2d89ca07990a9f3edc04c335763a67a97746a573b0afcce74ea46a46e6; PATH=/; DOMAIN=qq.com;
//  Pragma: no-cache
//	Cache-Control: no-cache; must-revalidate
//  Connection: Close
//	Content-Type: application/x-javascript; charset=utf-8

    QString strCookie;
    int nPos;
    int nIndex = 0;

    while (1)
    {
        strCookie = GetRespHeader(arrRespHeader, (L"Set-Cookie"), nIndex);
        if (strCookie == (""))
            break;

        nPos = strCookie.indexOf(("ptwebqq"));
        if (nPos >= 0)
            m_strPtWebQq = GetBetweenString(strCookie.toStdWString().c_str()+nPos+7, (L"="), (L";"));

        nPos = strCookie.indexOf(("skey"));
        if (nPos >=0 )
            m_strSKey = GetBetweenString(strCookie.toStdWString().c_str()+nPos+4, (L"="), (L";"));

        nIndex++;
    }

    return TRUE;
}


QQProtocol::QQProtocol()
{

}


int QQProtocol::CheckVerifyCode(QString strQQNum, QString strAppId, CVerifyCodeInfo * lpVCInfo)
{
//    获取验证码
//    用Web登录QQ时需要先打开web.qq.com，但我们用的是应用程序模拟浏览器登录，所以这一步是没有必要的，所以我们主要看看点击“登录”按钮时浏览器向服务器发送什么数据了。Web登录QQ输入帐号输入焦点离开时，有时会提示要输入验证码，那么第一步就是要看看什么样的QQ号需要输入验证码。
//    GET http://ptlogin2.qq.com/check?uin=1030196367&appid=1002101&r=0.8849248
//    “1030196367”是我测试用的QQ号，r的值是个随机数，写成固定的也行。
//    服务器返回“ptui_checkVC('0','!OMD');”
//    括号里有两个被逗号隔开的单引号引着的数据，第一个值如果为0，则第二值为验证码，即不需要再从服务器获取验证码图片了，这个就是验证码了；第一个值如果不是1，则需要从服务器获取验证码图片，验证码需要根据图片人工输入。

    QString strReqHeaders = "Accept: */*\r\nReferer: https://ui.ptlogin2.qq.com/cgi-bin/login?target=self&style=5&mibao_css=m_webqq&appid=1003903&enable_qlogin=0&no_verifyimg=1&s_url=http%3A%2F%2Fweb.qq.com%2Floginproxy.html&f_url=loginerroralert&strong_login=1&login_state=10&t=20130417001\r\nAccept-Language: zh-cn\r\n";
    QString strFmt = "http://check.ptlogin2.qq.com/check?uin=%1&appid=%2&r=0.23017793586962337";
    QString strUrl;
    int iRet  = YOUNG_ERROR;
    if (strQQNum.length() == 0 || strAppId.length() == 0 || NULL == lpVCInfo)
        return iRet;

    m_pManager = new QNetworkAccessManager(this);
    QNetworkRequest request;
    strUrl = strFmt.arg(strQQNum).arg(strAppId);
    request.setRawHeader("Accept", "*/*");
    request.setRawHeader("Referer","https://ui.ptlogin2.qq.com/cgi-bin/login?target=self&style=5&mibao_css=m_webqq&appid=1003903&enable_qlogin=0&no_verifyimg=1&s_url=http%3A%2F%2Fweb.qq.com%2Floginproxy.html&f_url=loginerroralert&strong_login=1&login_state=10&t=20130417001");
    request.setRawHeader("Accept-Language","zh-cn");
    request.setUrl(QUrl(strUrl));
    m_pReply =  m_pManager->get(request);

    QEventLoop eventLoop;
    connect(m_pReply,SIGNAL(finished()), &eventLoop, SLOT(quit()));
    eventLoop.exec();       //block until finish
    QByteArray bTmp = m_pReply->readAll();
    m_pReply->close();
    m_pReply->deleteLater();
    m_pManager->deleteLater();
    return lpVCInfo->Parse(bTmp);
}
int QQProtocol::CalcPwdHash(QString strQQPwd, QString strVerifyCode,
                            const char * lpPtUin, int nPtUinLen, wchar_t * lpPwdHash, int nLen)
{

    strVerifyCode = "!OOE";
    QByteArray bIn,bOut;
    bOut = QCryptographicHash::hash(strQQPwd.toUtf8(),QCryptographicHash::Md5 );

    bOut.resize(bOut.length() + nPtUinLen);
    memcpy(&bOut.data()[16], lpPtUin, nPtUinLen);
    bOut = QCryptographicHash::hash(bOut,QCryptographicHash::Md5 );

    bOut = bOut.toHex().toUpper();
    strVerifyCode = strVerifyCode.toUpper();

    bOut.append(strVerifyCode.toUtf8());
    bOut = QCryptographicHash::hash(bOut,QCryptographicHash::Md5 );
    bOut = bOut.toHex().toUpper();
    QTextCodec *codec = QTextCodec::codecForName("utf8");
    codec->toUnicode(bOut).toWCharArray(lpPwdHash);
    return 0;
}

int QQProtocol::Logon1(QString lpQQNum, QString lpQQPwd,
                       CVerifyCodeInfo *lpVerifyCode,
                       CLoginResult_1 * lpLoginResult1,QString lpAppId)
{
    QString lpszReqHeaders = ("Accept: */*\r\nReferer: http://ui.ptlogin2.qq.com/cgi-bin/login?target=self&style=5&mibao_css=m_webqq&appid=1003903&enable_qlogin=0&no_verifyimg=1&s_url=http%3A%2F%2Fweb.qq.com%2Floginproxy.html&f_url=loginerroralert&strong_login=1&login_state=10&t=20120504001\r\nAccept-Language: zh-cn\r\n");
    QString lpFmt = ("http://ptlogin2.qq.com/login?u=%s&p=%s&verifycode=%s      &webqq_type=10&remember_uin=1&login2qq=1&aid=%s&u1=http%%3A%%2F%%2Fweb.qq.com      %%2Floginproxy.html%%3Flogin2qq%%3D1%%26webqq_type%%3D10&h=1&ptredirect=0&ptlang		=2052&from_ui=1&pttype=1&dumy=&fp=loginerroralert&action=1-8-4593&mibao_css=m_webqq&t=1&g=1");

    wchar_t szQQNum[32] = {0}, szQQPwd[32] = {0}, szVerifyCode[32] = {0};
    wchar_t szPwdHash[64] = {0};
    wchar_t szUrl[1024] = {0};
    quint32 u32RespCode;
    std::vector<QString> arrRespHeader;

    if (0 == lpQQNum.length() || 0 == lpQQPwd.length() || NULL == lpVerifyCode || NULL == lpLoginResult1)
        return YOUNG_ERROR;

    lpQQNum.toWCharArray(szQQNum);
    lpQQPwd.toWCharArray(szQQPwd);
    lpVerifyCode->m_strVerifyCode.toWCharArray(szVerifyCode);

    CalcPwdHash(lpQQPwd, lpVerifyCode->m_strVerifyCode, lpVerifyCode->m_cPtUin, lpVerifyCode->m_nPtUinLen, szPwdHash, sizeof(szPwdHash)/sizeof(wchar_t));

    wsprintf(szUrl, lpFmt.toStdWString().c_str(), szQQNum, szPwdHash, szVerifyCode, lpAppId.toStdWString().c_str());
    m_pManager = new QNetworkAccessManager(this);
    QNetworkRequest request;
    QString strUrl = QString::fromWCharArray(szUrl);
    request.setRawHeader("Accept", "*/*");
    request.setRawHeader("Referer","http://ui.ptlogin2.qq.com/cgi-bin/login?target=self&style=5&mibao_css=m_webqq&appid=1003903&enable_qlogin=0&no_verifyimg=1&s_url=http%3A%2F%2Fweb.qq.com%2Floginproxy.html&f_url=loginerroralert&strong_login=1&login_state=10&t=20120504001");
    request.setRawHeader("Accept-Language","zh-cn");
    request.setUrl(QUrl(strUrl));

    m_pReply =  m_pManager->get(request);

    QEventLoop eventLoop;
    connect(m_pReply,SIGNAL(finished()), &eventLoop, SLOT(quit()));
    eventLoop.exec();       //block until finish

    lpLoginResult1->Parse(&m_pReply->readAll(), &arrRespHeader);
    return 0;
}
